Content Guidelines: Add AI-powered generate/improve UI via Jetpack#47959
Content Guidelines: Add AI-powered generate/improve UI via Jetpack#47959aagam-shah wants to merge 65 commits intotrunkfrom
Conversation
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! Jetpack plugin: No scheduled milestone found for this plugin. If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack. |
Code Coverage SummaryCoverage changed in 1 file.
1 file is newly checked for coverage.
Full summary · PHP report · JS report If appropriate, add one of these labels to override the failing coverage check:
Covered by non-unit tests
|
|
Thanks for getting this started @aagam-shah. Here are a few comments based on what I see right now: 1. Badges 2. Suggestions The suggestions are presented in what appears like a disabled field: The container should look and behave like a regular input (but have a green border). We need to match the height of the input (and visa versa) to prevent layout shift. We also can accept a suggestion if someone clicks on the suggestion to start editing it. When the section is open, we don't need to show the suggestion badge any longer since the input + buttons communicate the suggestion. This is what I had in the design:
3. Banner behaviour The main banner dismisses if you generate a suggestion from within a section. The causes the layout to shift and feels jarring. The banner should only dismiss if the user dismisses it or the main call to action is used to generate guidelines for all the sections. 4. Block suggestions I'm not seeing any block suggestions being added. Are you planning on adding those separately? We should have suggestions for the block section as well as the blocks themselves.
|
dfbee81 to
3c42428
Compare
|
Thanks for the detailed feedback @fditrapani! Here's where we're at on each point: 1. Badges 2. Suggestions 3. Banner behaviour 4. Block suggestions |
|
Thanks for the updates @aagam-shah!
Sounds good to me if this is the badge we're already using. I understand we're updating components but hopefully this will get updates along with the others when that happens.
Thanks for the updates. This is looking better. We still have some shifting happening if the text area isn't the default size: Screen.Recording.2026-04-08.at.12.51.15.PM.mov
Nice! looking better here too. I noticed a bug where the banner unexpectedly goes away if you accept a suggestion. Screen.Recording.2026-04-08.at.12.53.02.PM.movJetpack logoI got some feedback from Devin that the logo should be reversed instead of the regular colour. (p1775665181650579/1775564866.152469-slack-C08NFD7RA58) Can we update the logo to look like this:
|
0b4325a to
e03390e
Compare
|
Thanks @fditrapani! Here's an update on the latest changes: 1. Suggestions UX — Updated:
2. Banner behaviour — Fixed:
3. Block suggestions — Still planned as a follow-up. 4. Upgrade notice — Added a persistent warning Notice (instead of snackbar) with a "View plans" button when AI is unavailable. Matches the standard WordPress notice pattern. |
Injects an AI-powered "Generate with Jetpack" button next to each "Save guidelines" button on the Content Guidelines settings page. Uses DOM injection via MutationObserver to find accordion forms and render React buttons that call the suggest-guidelines API endpoint. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pass AI availability, connection status, and upgrade URL from PHP to JS - Show contextual snackbar with action link when AI is unavailable: - Not connected: "Connect" action linking to Jetpack dashboard - Connected but no AI: "Upgrade" action linking to checkout - wpcom vs self-hosted sites get appropriate upgrade URLs - Disconnect MutationObserver once all buttons are injected - Inline buttons next to Save guidelines in a flex row Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Content Guidelines page is registered with slug 'guidelines-wp-admin', not 'content-guidelines-wp-admin'. Without this fix the script never enqueues. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Split monolithic 146-line JS file into: - constants.js (store name, sections, API path) - lib/api.js (suggest-guidelines API wrapper) - lib/inject.js (DOM injection + MutationObserver) - components/generate-button.jsx (per-section button) Entry point is now a thin import + init. Button label changes to "Improve with Jetpack" when content exists. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New SuggestAllButton component generates all 4 guideline sections at once. Injected into the .admin-ui-page__header via DOM injection. Label adapts: "Generate guidelines" when empty, "Improve guidelines" when content exists. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows a Jetpack-branded card above the guideline list when all sections are empty, encouraging users to generate their first set of guidelines. Hides automatically when content exists. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Target .admin-ui-page__header-actions instead of .admin-ui-page__header so the button renders in the header row next to the title, not below the subtitle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Option B design only has the top-level "Generate/Improve guidelines" button and the empty state banner. Per-section buttons are not part of the design. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add wp.data store (jetpack/content-guidelines-ai) for shared suggestion state across injected React roots - Show "Suggestion" badge in accordion headers when a suggestion exists - Show loading spinner in accordion headers while generating - Show suggestion preview with Accept/Dismiss inside expanded accordions - Accept writes to core/content-guidelines store, Dismiss discards - Header button now writes to suggestion store instead of directly to the guideline store Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add per-section "Improve/Generate guidelines" tertiary button in each accordion's button row (triggers single-section AI generation) - When suggestion exists: hide Gutenberg's DataForm + Save/Clear via CSS class toggle, show suggestion textarea + Accept/Dismiss instead - Add Jetpack icon SVG to the header "Improve guidelines" button - Add per-section loading state to the store so each accordion shows its own spinner independently - Update suggestion badge to use per-section loading Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Review fixes: - Extract shared availability check to lib/availability.js - Centralize config in constants.js - MutationObserver disconnects once all injections complete - Remove unused store actions/selectors - Add useEffect cleanup for DOM class manipulation - Use Jetpack CSS custom properties for colors Banner upgrade: - Rich dark gradient background with green orb decorations - Matches exploration-b prototype design - Shows when all guidelines empty, hides automatically - No localStorage persistence — purely data-driven Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
JetpackLogo component has transparent paths that let the blue button background bleed through. Use inline SVG with explicit white fill for the lightning bolt instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The overlay approach introduced DOM reparenting of React-managed elements which is an anti-pattern. Revert to the simpler approach of hiding Gutenberg's form and showing our diff container. Improved selectors: target .dataforms-layouts__wrapper and .components-h-stack by known class names instead of the fragile :first-child > :not(...) structural selector. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 1px green border (no box-shadow), 2px border-radius, 9px 11px padding - Dynamic height via CSS variable read from textarea before hiding - Prevents layout shift when toggling between textarea and diff view Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move bannerDismissed to the AI store instead of cross-reading localStorage between separate React roots. Both components now subscribe to the same store selector. localStorage is still used for persistence across page loads, but only read on store init and written in the dismissBanner action. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Banner visibility now based solely on bannerDismissed store state, not on whether guidelines exist. Prevents banner from hiding when a suggestion is accepted (which writes to the guideline store). Jetpack logo reversed to white circle with green lightning for better contrast on the primary button, per design feedback. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Triangles sit on top of the white circle in the SVG stacking order, so transparent shows white not the button. Use the WP components accent color variable to match the button bg. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This component uses a single SVG path with cutout triangles, so the button background naturally shows through the lightning bolt. No CSS overrides needed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Read the textarea's current value from the DOM before hiding it, so the diff reflects unsaved edits the user may have made. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sync textarea height with the captured CSS variable so accepting a suggestion doesn't reset the textarea to its default height. The variable persists on the form after accept, keeping both the diff container and textarea at the same height. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drop the fragile CSS variable height matching. Both the diff container and textarea now size naturally to their content. Diff container scrolls if content overflows. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use ResizeObserver to continuously track the textarea's height in a ref while it's visible. When the suggestion appears, the diff container uses the captured height as inline style. This handles user-resized textareas without timing issues. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of tracking textarea height in JS, make the diff container resizable like the textarea. Both elements size to their content naturally and the user can resize either. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Read offsetHeight once when suggestion first arrives (textarea still visible), store in state so it triggers a re-render with the correct inline height on the diff container. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
API now uses categories-based format:
Request: { categories: { site: {}, copy: { guidelines: "..." } } }
Response: { site: { guidelines: "..." }, copy: { guidelines: "..." } }
Translation is contained in api.js — callers unchanged.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show a warning Notice with "View plans" button instead of a transient snackbar when Jetpack AI is unavailable. The notice is injected above the guideline list, dismissible, and managed via the AI store. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add box-sizing: border-box so the Notice's border and padding are included in the 680px width, aligning with the accordions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
b68d8ed to
9b3b41f
Compare
|
Nice work @aagam-shah. This is looking great. One really minor thing! When you hover over a suggestion field, we show the pointer cursor. It's not technically wrong but the text cursor does a better job at indicating that it's editable. |
Mirrors SectionGenerateButton for the block guideline editing modal. Reads textarea value from DOM, calls suggestGuidelines API, and stores the suggestion in Redux using the block name as the store key. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add block-level injection points in inject.js for the block guideline modal. Imports BlockGenerateButton and BlockSuggestionActions components, registers their slots, adds getBlockNameFromModal helper to extract the block name from modal inputs, and injects both components into the modal when it is open. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add "Improve guidelines" / "Generate guidelines" AI feature to the block guideline editing modal, mirroring the existing section-level feature. - BlockSuggestionActions: diff view with shimmer and class toggling - BlockSuggestionButtons: Improve/Accept/Dismiss buttons row - DiffView: shared diff rendering component (used by sections and blocks) - lib/dom.js: shared setTextareaValue and acceptBlockSuggestion helpers - Block-specific shimmer CSS applied directly on textarea background - Clears stale suggestions on modal close Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…es-plugin-extensibility
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Hey @fditrapani , I've added the Improve/Generate guidelines flow to the block edit modal — shimmer loading, word-level diff, accept/dismiss all working. For showing suggestions in the block list (DataViews table), the injection is getting complex since DataViews doesn't expose easy extension points and the row/action structure is harder to hook into compared to the modal. So for now suggestions are scoped to the edit modal. |









Summary
Adds AI-powered guideline generation to the WordPress Content Guidelines admin page via Jetpack. Users can generate guidelines from scratch or improve existing ones, with word-level diffs for review before accepting.
What it does
Architecture
Uses DOM injection — Jetpack enqueues a standalone JS+CSS bundle on
settings_page_guidelines-wp-admin, uses MutationObserver to inject React components, and shares state via awp.datastore.Related
Testing instructions
Note: AI suggestions are currently mocked for testing. Flip
MOCKtofalsein_inc/content-guidelines-ai/lib/api.jsand remove thereturn falseinlib/availability.jsto use the real API.pnpm jetpack build plugins/jetpackDoes this pull request change what data or activity we track or use?
No. This PR sends site content to the existing Jetpack AI suggest-guidelines endpoint (added in #47479) when the user explicitly clicks a generate button. No new tracking, analytics events, or data collection is introduced.
🤖 Generated with Claude Code